﻿// (c) Copyright Microsoft Corporation.
// This source is subject to [###LICENSE_NAME###].
// Please see [###LICENSE_LINK###] for details.
// All other rights reserved.

using System;
using System.Windows;
using System.Windows.Controls;

namespace EnsureWeb.Controls
{
    /// <summary>
    /// Timeline Item control.
    /// </summary>
    [TemplatePart(Name = TimelineItem.ElementBarButton, Type = typeof(CheckBox))]
    [TemplatePart(Name = TimelineItem.ElementTextButton, Type = typeof(Button))]

    [TemplateVisualState(Name = TimelineItem.StateNormal, GroupName = TimelineItem.GroupCommon)]
    [TemplateVisualState(Name = TimelineItem.StateDisabled, GroupName = TimelineItem.GroupCommon)]
    public class TimelineItem : Control
    {
        #region Template part names
        /// <summary>
        /// Bar button template element.
        /// </summary>
        private const string ElementBarButton = "BarButton";

        /// <summary>
        /// The text button template element.
        /// </summary>
        private const string ElementTextButton = "TextButton";

        #endregion

        #region Template VisualState names

        /// <summary>
        /// Common state group.
        /// </summary>
        private const string GroupCommon = "CommonStates";

        /// <summary>
        /// Normal state of the Common state group.
        /// </summary>
        private const string StateNormal = "Normal";

        /// <summary>
        /// Disabled state of the Common state group.
        /// </summary>
        private const string StateDisabled = "Disabled";

        #endregion

        /// <summary>
        /// The bar button.
        /// </summary>
        private CheckBox BarButton;

        /// <summary>
        /// The text button.
        /// </summary>
        private Button TextButton;

        #region public string Text

        /// <summary>
        /// Gets or sets the text property.
        /// </summary>
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        /// <summary>
        /// The TimelineItem.TextProperty.
        /// </summary>
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), typeof(TimelineItem), new PropertyMetadata(string.Empty, OnTextChanged));

        /// <summary>
        /// Execute when Text changed.
        /// </summary>
        /// <param name="d">Source control.</param>
        /// <param name="e">Event args.</param>
        private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TimelineItem control = d as TimelineItem;
            string value = (string)e.NewValue;
            if (control != null)
            {
                control.OnTextChanged(value);
            }
        }
        #endregion

        #region public bool CanDrilldown
        /// <summary>
        /// Gets or sets a value indicating whether the item can drill down.
        /// </summary>
        public bool CanDrilldown
        {
            get { return (bool)GetValue(CanDrilldownProperty); }
            set { SetValue(CanDrilldownProperty, value); }
        }

        /// <summary>
        /// Whether the item can drill down.
        /// </summary>
        public static readonly DependencyProperty CanDrilldownProperty =
            DependencyProperty.Register("CanDrillDown", typeof(bool), typeof(TimelineItem), new PropertyMetadata(true, OnCanDrilldownChanged));

        /// <summary>
        /// The drill down property changed.
        /// </summary>
        /// <param name="d">Source control.</param>
        /// <param name="e">Event args.</param>
        private static void OnCanDrilldownChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TimelineItem control = d as TimelineItem;
            bool value = (bool)e.NewValue;
            if (control != null)
            {
                control.OnCanDrilldownChanged(value);
            }
        }

        /// <summary>
        /// Handle drill down property changed.
        /// </summary>
        /// <param name="value">New value.</param>
        protected void OnCanDrilldownChanged(bool value)
        {
            if (this.TextButton == null)
            {
                return;
            }

            this.TextButton.IsEnabled = value;
        }
        #endregion

        #region public bool IsSelected

        /// <summary>
        /// Gets or sets a value indicating whether this item is "IsSelected".
        /// </summary>
        public bool IsSelected
        {
            get { return (bool)GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); }
        }

        /// <summary>
        /// The IsSelected property.
        /// </summary>
        public static readonly DependencyProperty IsSelectedProperty =
            DependencyProperty.Register("IsSelected", typeof(bool), typeof(TimelineItem), new PropertyMetadata(false, OnIsSelectedChanged));

        /// <summary>
        /// Execute when IsSelected value changed.
        /// </summary>
        /// <param name="d">Source object.</param>
        /// <param name="e">Event args.</param>
        private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TimelineItem control = d as TimelineItem;

            if (control != null)
            {
                control.OnIsSelectedChanged((bool)e.NewValue);
            }
        }

        /// <summary>
        /// Execute when IsSelected property changed.
        /// </summary>
        /// <param name="value">The new value.</param>
        protected virtual void OnIsSelectedChanged(bool value)
        {
            if (this.BarButton != null)
            {
                this.BarButton.IsChecked = value;
            }
        }
        #endregion

        #region public bool CanSelect

        /// <summary>
        /// Gets or sets a value indicating whether the item is seleactable.
        /// </summary>
        public bool CanSelect
        {
            get { return (bool)GetValue(CanSelectedProperty); }
            set { SetValue(CanSelectedProperty, value); }
        }

        /// <summary>
        /// Can selected property.
        /// </summary>
        public static readonly DependencyProperty CanSelectedProperty =
            DependencyProperty.Register("CanSelected", typeof(bool), typeof(TimelineItem), new PropertyMetadata(true, OnCanSelectedChanged));

        /// <summary>
        /// Handle CanSelected property changed.
        /// </summary>
        /// <param name="d">Event source.</param>
        /// <param name="e">Event args.</param>
        private static void OnCanSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TimelineItem control = d as TimelineItem;
            bool value = (bool)e.NewValue;

            if (control != null)
            {
                control.OnCanSelectedChanged(value);
            }
        }

        /// <summary>
        /// Handle CanSelected property changed.
        /// </summary>
        /// <param name="value">New value of CanSelected.</param>
        protected virtual void OnCanSelectedChanged(bool value)
        {
            if (this.BarButton != null)
            {
                this.BarButton.IsEnabled = value;
            }
        }
        #endregion

        #region public bool ShowText
        /// <summary>
        /// Gets or sets a value indicating whether to show the text of TextButton.
        /// </summary>
        public bool ShowText
        {
            get { return (bool)GetValue(ShowTextProperty); }
            set { SetValue(ShowTextProperty, value); }
        }

        /// <summary>
        /// The dependency property of ShowText.
        /// </summary>
        public static readonly DependencyProperty ShowTextProperty =
            DependencyProperty.Register("ShowText", typeof(bool), typeof(TimelineItem), new PropertyMetadata(true, OnShowTextChanged));

        /// <summary>
        /// Handle the ShowText property change.
        /// </summary>
        /// <param name="d">The source object.</param>
        /// <param name="e">The event args.</param>
        private static void OnShowTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TimelineItem control = d as TimelineItem;
            bool value = (bool)e.NewValue;
            if (control != null)
            {
                control.OnShowTextChanged(value);
            }
        }

        /// <summary>
        /// Handle the ShowText property changed.
        /// </summary>
        /// <param name="value">The new value of ShowText.</param>
        protected virtual void OnShowTextChanged(bool value)
        {
            if (this.TextButton != null)
            {
                this.TextButton.Content = value ? this.Text : string.Empty;
            }
        }

        #endregion

        #region public DateTime DateTime
        /// <summary>
        /// Gets or sets the selected date.
        /// </summary>
        public DateTime DateTime
        {
            get { return (DateTime)GetValue(DateTimeProperty); }
            set { SetValue(DateTimeProperty, value); }
        }

        /// <summary>
        /// Selected date.
        /// </summary>
        public static readonly DependencyProperty DateTimeProperty =
            DependencyProperty.Register("DateTime", typeof(DateTime), typeof(TimelineItem), new PropertyMetadata(DateTime.MinValue));

        #endregion

        /// <summary>
        /// Initializes a new instance of the TimelineItem class.
        /// </summary>
        public TimelineItem()
        {
            DefaultStyleKey = typeof(TimelineItem);
        }

        /// <summary>
        /// Text clicked event.
        /// </summary>
        public event EventHandler ClickText;

        /// <summary>
        /// Bar clicked event.
        /// </summary>
        public event EventHandler ClickBar;

        /// <summary>
        /// Invoked whenever application code or an internal process, such as a
        /// rebuilding layout pass, calls the ApplyTemplate method.
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            this.BarButton = GetTemplateChild(ElementBarButton) as CheckBox;
            this.TextButton = GetTemplateChild(ElementTextButton) as Button;

            if (this.BarButton != null)
            {
                this.BarButton.Click += (o, e) =>
                {
                    EventHandler handler = ClickBar;
                    if (handler != null)
                    {
                        handler(this, EventArgs.Empty);
                    }
                };
            }

            if (this.TextButton != null)
            {
                this.TextButton.Click += (o, e) =>
                {
                    EventHandler handler = ClickText;
                    if (handler != null)
                    {
                        handler(this, EventArgs.Empty);
                    }
                };
            }

            OnTextChanged(this.Text);
            OnCanDrilldownChanged(this.CanDrilldown);
            OnIsSelectedChanged(this.IsSelected);
            OnCanSelectedChanged(this.CanSelect);
            OnShowTextChanged(this.ShowText);
            UpdateVisualState(true);
        }

        /// <summary>
        /// Execute when text is changed.
        /// </summary>
        /// <param name="value">New value of text.</param>
        private void OnTextChanged(string value)
        {
            if (this.TextButton == null)
            {
                return;
            }

            if (this.ShowText)
            {
                this.TextButton.Content = value;
            }
        }

        /// <summary>
        /// Update the current visual state of the button.
        /// </summary>
        /// <param name="useTransitions">
        /// true to use transitions when updating the visual state, false to
        /// snap directly to the new visual state.
        /// </param>
        private void UpdateVisualState(bool useTransitions)
        {
            ChangeVisualState(useTransitions);
        }

        /// <summary>
        /// Change to the correct visual state for the button.
        /// </summary>
        /// <param name="useTransitions">
        /// true to use transitions when updating the visual state, false to
        /// snap directly to the new visual state.
        /// </param>
        private void ChangeVisualState(bool useTransitions)
        {
            if (!IsEnabled)
            {
                GoToState(useTransitions, StateDisabled);
            }
            else
            {
                GoToState(useTransitions, StateNormal);
            }
        }

        /// <summary>
        /// Call VisualStageManager to change state
        /// </summary>
        /// <param name="useTransitions">
        /// true to use transitions when updating the visual state, false to
        /// snap directly to the new visual state.
        /// </param>
        /// <param name="stateName">The state name.</param>
        private void GoToState(bool useTransitions, string stateName)
        {
            VisualStateManager.GoToState(this, stateName, useTransitions);
        }
    }
}
